package com.vinjogames.util;

import android.app.Activity;
import android.graphics.PointF;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;

import com.vinjogames.TankGame.TankGameActivity;
import com.vinjogames.entities.Game;
import com.vinjogames.gfx.Camera;
import com.vinjogames.gfx.GameRenderer;
import com.vinjogames.ui.TitleMenu;

public class InputManager {

	public static final int CANCELDISTANCE = 10;

	private Camera mCamera;
	private Game mGame;
	private TitleMenu mMenu;
	private Activity mActivity;
	private ScaleGestureDetector mScaleGD;

	private float downX;
	private float downY;

	private float moveX;
	private float moveY;
	PointF GLLocation;
	PointF WorldLocation;
	PointF ScreenLocation;
	PointF tempPointF;

	private Handler handler = new Handler();
	private Runnable downLoop = new Runnable(){
		@Override
		public void run() {
			tempPointF.set(downX,downY);
			sendAction(GameConVars.INPUT_DOWN, tempPointF,0);
			handler.postDelayed(downLoop, 100);//Send every 100ms
		}
	};

	private InputManager(){};

	private static class InputManagerHolder {
		public static final InputManager instance = new InputManager();
	}

	public static InputManager getInstance(){
		return InputManagerHolder.instance;
	}
	
	public void init(TankGameActivity activity){
		mGame = activity.getGame();
		mMenu = activity.getMenu();
		mCamera = Camera.getInstance();
		mActivity = activity;

		downX = -1;
		downY = -1;

		moveX = -1;
		moveY = -1;

		mScaleGD = new ScaleGestureDetector(mActivity, new ScaleListener());
		
		GLLocation = new PointF();
		WorldLocation = new PointF();
		ScreenLocation = new PointF();
		tempPointF = new PointF();
	}

	public void handleTouchEvent(MotionEvent e){
		if(!GameRenderer.renderStarted()) return;
		
		mScaleGD.onTouchEvent(e);
		ScreenLocation.set(e.getX(), e.getY());
		WorldLocation.set(mCamera.getWorldX(e.getX()), mCamera.getWorldY(e.getY()));
		GLLocation.set(mCamera.getGLX(e.getX()), mCamera.getGLY(e.getY()));


		switch(e.getAction() & MotionEvent.ACTION_MASK){
		//Another finger is detected.
		case MotionEvent.ACTION_POINTER_DOWN:
			// If true, probably means we want to zoom (in this implementation)
			break;
		case MotionEvent.ACTION_DOWN:
			if(downX < 0){ //&& startY < 0){
				downX = e.getX();
				downY = e.getY();
			}
			handler.post(downLoop);
			break;
		case MotionEvent.ACTION_POINTER_UP:
		case MotionEvent.ACTION_UP:
			handler.removeCallbacks(downLoop);
			if((Math.abs(e.getX() - downX) < CANCELDISTANCE) ||
					(Math.abs(e.getY() - downY) < CANCELDISTANCE)){
				sendAction(GameConVars.INPUT_TAP, ScreenLocation,0);
			}
			sendAction(GameConVars.INPUT_UP, ScreenLocation, 0);
			downX = -1;
			downY = -1;
			moveX = -1;
			moveY = -1;
			break;
		case MotionEvent.ACTION_MOVE:
			//Logger.log("[InputManager]: Move");
			if(moveX >= 0) {			
				if(!mScaleGD.isInProgress()) {		
					WorldLocation.set(WorldLocation.x - mCamera.getWorldX(moveX), WorldLocation.y - mCamera.getWorldY(moveY));
					sendAction(GameConVars.INPUT_DRAG,WorldLocation, 0);
				}
			}
			moveX = e.getX();
			moveY = e.getY();
			break;
		}
	}

	public void sendAction(int action, PointF location, float scale){
		switch(action){
		case GameConVars.INPUT_TAP:
			//Logger.log("Pixel  x: " + location.x + " y: " + location.y);
			//Logger.log("Screen x: " + GLLocation.x + " y: " + GLLocation.y);
			//Logger.log("World  x: " + WorldLocation.x + " y: " + WorldLocation.y);

			if(!mGame.hasStarted()){
				mMenu.handleTouch(GLLocation);
			}else{
				mGame.getGUI().handleAction(action, location);
			}
			break;
		case GameConVars.INPUT_DOWN:
			if(mGame.hasStarted()){
				mGame.getGUI().handleAction(action, location);
			}
			break;
		case GameConVars.INPUT_DRAG:
			if(!mGame.hasStarted()) return;
			if(mGame.getCurrentUnit() != null){
				mGame.getGUI().handleAction(action, ScreenLocation);
			}else{
				if(!mGame.getGUI().hasAMenuShown())
					mCamera.move(location.x, location.y);
			}
			break;
		case GameConVars.INPUT_ZOOM:
			if(!mGame.hasStarted() || mGame.getGameState() != mGame.IDLE) return;
			if(AIDriver.getInstance().getState() != 0 /* IDLE */) return;
			mCamera.zoom(scale, location);
			break;
		case GameConVars.INPUT_MENU:
			//Logger.log("[InputManager] - Menu pressed!");
			mGame.onMenuButton();
			break;
		case GameConVars.INPUT_QUIT:
			break;
		case GameConVars.INPUT_UP:
			if(!mGame.hasStarted()) return;
			if(mGame.getCurrentUnit() != null)
				mGame.getGUI().handleAction(action, location);
			break;
		}
	}

	public Camera getCamera(){ return mCamera; }

	private class ScaleListener extends ScaleGestureDetector.SimpleOnScaleGestureListener{
		@Override
		public boolean onScale(ScaleGestureDetector detector){
			tempPointF.set(detector.getFocusX(),detector.getFocusY());
			sendAction(GameConVars.INPUT_ZOOM, tempPointF,detector.getScaleFactor() );
			return true;
		}
	}
	
	public void quit(){
		((TankGameActivity)mActivity).onBackPressed();
		//MemoryManager.getInstance().initializeManager(0, 0, 0, 0);
		//MemoryManager.getInstance().clearMemory();
		//System.exit(0); //TODO:  this is needed to clear memory at end, need to find a better way
	}
}
